#include <stdio.h>
// 添加字库头文件
#include "font.h"
#include <string.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 添加输入模型头文件
#include <linux/input.h>
#include <unistd.h>
#include <sys/mman.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
// 添加串口头文件
#include <termios.h>
#include <unistd.h>
#include <string.h>

unsigned int *lcd; // 全局变量，所有函数都可以访问

font *f;

// 映射LCD 设备
int mmap_lcd()
{
    // 1.打开LCD 设备
    int fd = open("/dev/fb0", O_RDWR);
    if (fd == -1)
    {
        printf("open lcd fail:");
        return -1;
    }
    else
    {
        printf("open lcd success\n");
    }

    // 2.mmap 映射LCD设备
    lcd = mmap(NULL, 800 * 480 * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if (lcd == MAP_FAILED)
    {
        printf("mmap fail:");
        return -1;
    }
    else
    {
        printf("mmap success\n");
    }
}

// 初始化字库
int init_font(int size)
{
    // 1.加载字库文件
    f = fontLoad("/usr/share/fonts/DroidSansFallback.ttf");
    if (f == NULL)
    {
        printf("Failed to load font file\n");
        return -1;
    }

    // 2.设置字体大小
    fontSetSize(f, size);
}
// 显示汉字接口
void show_text(int x, int y, int w, int h, char *text, int color, int width)
{
    bitmap *bm = createBitmap(w, h, 4);

    fontPrint(f, bm, 0, 0, text, color, width);

    show_font_to_lcd(lcd, x, y, bm);

    destroyBitmap(bm);
}

// 图像显示接口
int display_image(const char *path)
{

    // 2.对LCD设备进行内存映射
    int(*p)[800] = (void *)lcd;

    // 3 .  打开图片文件
    int bmp = open(path, O_RDWR);
    if (bmp < 0)
    {
        perror("open bmp error");
        return -1;
    }
    else
    {
        printf("open bmp success\n");
    }

    // 4. 读取bmp 头数据
    char head[54] = {0};
    read(bmp, head, 54);

    // 5.解析头数据
    int width = *(int *)&head[18];
    int height = *(int *)&head[22];

    printf("width:%d,height:%d\n", width, height);

    // 7.把rgb 转换为 argb
    char argb[800 * 480 * 4];

    read(bmp, argb, 800 * 480 * 4);

    // 8.把 argb 转换为与映射地址匹配的类型
    int(*color)[800] = (void *)argb;

    // 9.把颜色数据放入映射地址
    for (int y = 0; y < 480; y++)
    {
        for (int x = 0; x < 800; x++)
        {
            p[y][x] = color[479 - y][x];
        }
    }

    // 10 .关闭所有打开后的设备
    close(bmp);
}

// 获取触摸屏坐标点
int get_touch(int *x, int *y)
{

    // 1.打开触摸屏设备文件
    int fd = open("/dev/input/event0", O_RDWR);
    if (fd < 0)
    {
        printf("open touchscreen device file failed\n");
        return -1;
    }

    while (1)
    {
        // 2.读取触摸屏输入信息到输入模型中
        struct input_event ev;
        read(fd, &ev, sizeof(ev));

        // 处理输入事件获取X轴的值
        if (ev.type == EV_ABS && ev.code == ABS_X)
        {
            // 3.处理输入事件，获取X轴的值
            // printf("X axis value: %d\n", ev.value);
            *x = ev.value * 800 / 1020;
        }

        // 处理输入事件获取Y轴的值
        if (ev.type == EV_ABS && ev.code == ABS_Y)
        {
            // 3.处理输入事件，获取Y轴的值
            // printf("Y axis value: %d\n", ev.value);
            *y = ev.value * 480 / 600;
        }

        // 获取触摸屏的按压状态
        if (ev.type == EV_KEY && ev.code == BTN_TOUCH)
        {
            if (ev.value == 0)
            {
                // printf("Touch released\n");
                break; // 跳出循环
            }

            if (ev.value == 1)
            {
                // printf("Touch pressed\n");
            }
        }
    }

    close(fd);
}

// 封装一个键盘
int Keyboard(int x, int y)
{
    // 按键 1 2 3
    if (x > 30 && x < 95 && y > 110 && y < 180)
    {
        return 1;
    }
    if (x > 110 && x < 175 && y > 110 && y < 180)
    {
        return 2;
    }
    if (x > 195 && x < 260 && y > 110 && y < 180)
    {
        return 3;
    }
    // 按键 4 5 7
    if (x > 30 && x < 95 && y > 200 && y < 270)
    {
        return 4;
    }
    if (x > 110 && x < 175 && y > 200 && y < 270)
    {
        return 5;
    }
    if (x > 195 && x < 260 && y > 200 && y < 270)
    {
        return 6;
    }

    // 按键 7 8 9
    if (x > 30 && x < 95 && y > 290 && y < 360)
    {
        return 7;
    }
    if (x > 110 && x < 175 && y > 290 && y < 360)
    {
        return 8;
    }
    if (x > 195 && x < 260 && y > 290 && y < 360)
    {
        return 9;
    }

    // 按键 0 .  确定
    if (x > 30 && x < 95 && y > 375 && y < 445)
    {
        return 0;
    }
    if (x > 110 && x < 175 && y > 375 && y < 445)
    {
        return -1; //-1 表示点
    }
    if (x > 195 && x < 370 && y > 375 && y < 445)
    {
        return -2; // -2 表示确定
    }

    // 按键 退出 退格  清空
    if (x > 280 && x < 370 && y > 110 && y < 180)
    {
        return -3; // -3 表示退出
    }
    if (x > 280 && x < 370 && y > 200 && y < 270)
    {
        return -4; // -4 表示退格
    }
    if (x > 280 && x < 370 && y > 290 && y < 360)
    {
        return -5; //  -5 表示清空
    }

    // 读卡
    if (x > 690 && x < 785 && y > 410 && y < 470)
    {
        return 99;
    }

    // 注册
    if (x > 425 && x < 575 && y > 85 && y < 150)
    {
        return 88;
    }

    // 注销
    if (x > 600 && x < 750 && y > 85 && y < 150)
    {
        return 77;
    }

    // 查询
    if (x > 425 && x < 575 && y > 195 && y < 260)
    {
        return 66;
    }

    // 充值
    if (x > 605 && x < 755 && y > 195 && y < 260)
    {
        return 55;
    }

    // 消费
    if (x > 610 && x < 760 && y > 300 && y < 360)
    {
        return 44;
    }

}

int set_serial_uart(int ser_fd)
{
    struct termios new_cfg, old_cfg;

    /*保存并测试现有串口参数设置，在这里如果串口号等出错，会有相关的出错信息*/
    if (tcgetattr(ser_fd, &old_cfg) != 0)
    {
        perror("tcgetattr");
        return -1;
    }

    bzero(&new_cfg, sizeof(new_cfg));
    /*原始模式*/
    /* 设置字符大小*/
    new_cfg = old_cfg;
    cfmakeraw(&new_cfg); /* 配置为原始模式 */

    /*波特率为9600*/
    cfsetispeed(&new_cfg, B9600);
    cfsetospeed(&new_cfg, B9600);

    new_cfg.c_cflag |= CLOCAL | CREAD;

    /*8位数据位*/
    new_cfg.c_cflag &= ~CSIZE;
    new_cfg.c_cflag |= CS8;

    /*无奇偶校验位*/
    new_cfg.c_cflag &= ~PARENB;

    /*1位停止位*/
    new_cfg.c_cflag &= ~CSTOPB;
    /*清除串口缓冲区*/
    tcflush(ser_fd, TCIOFLUSH);

    new_cfg.c_cc[VTIME] = 0;
    new_cfg.c_cc[VMIN] = 1; // 接收一个字节立即返回
    tcflush(ser_fd, TCIOFLUSH);
    /*串口设置使能*/
    tcsetattr(ser_fd, TCSANOW, &new_cfg);
}

// 读卡函数
char *get_rfid(char *rfid)
{
    // 1.打开串口设备
    int fd = open("/dev/ttySAC2", O_RDWR);
    if (fd < 0)
    {
        perror("打开串口失败\n");
        return NULL;
    }

    // 2.配置串口协议
    set_serial_uart(fd);

    // 3.设计请求协议
    char requst[8] = {0};
    requst[0] = 0x07; // 帧长
    requst[1] = 0x02; // 命令类型
    requst[2] = 0x41; // 命令
    requst[3] = 0x01; // 长度
    requst[4] = 0x52; // 信息
    char BCC = 0;     // 校验和
    for (int i = 0; i < (requst[0] - 2); i++)
    {
        BCC ^= requst[i];
    }
    requst[5] = ~BCC; // 校验和
    requst[6] = 0x03; // 结束标志

    // 发起请求
    write(fd, requst, 7);

    // 读取RFID 模块返回的信息
    char ret[9] = {0};
    read(fd, ret, 9);
    if (ret[2] == 0x00)
    {
        printf("请求成功\n");

        // 防碰撞协议
        char Collision[9] = {0};
        Collision[0] = 0x08;
        Collision[1] = 0x02;
        Collision[2] = 0x42;
        Collision[3] = 0x02;
        Collision[4] = 0x93;
        Collision[5] = 0x00;
        char BCC = 0; // 校验和
        for (int i = 0; i < (Collision[0] - 2); i++)
        {
            BCC ^= Collision[i];
        }
        Collision[6] = ~BCC; // 校验和
        Collision[7] = 0x03;

        // 发送防碰撞
        write(fd, Collision, 8);

        // 读取卡号
        char id[11] = {0};
        read(fd, id, 11);

        if (id[2] == 0x0)
        {
            printf("读卡成功\n");
            sprintf(rfid, "%x%x%x%x", id[7], id[6], id[5], id[4]);

            printf("卡号:%s\n", rfid);
            return rfid;
        }
        else
        {
            printf("读卡失败\n");
            return NULL;
        }
    }
    else
    {
        printf("请求失败\n");
        return NULL;
    }
}

// 设置一个卡结构体
struct card
{
    char rfid[1024]; // 卡号
    int money;       // 当前卡的金额
};

struct card arry[1024]; // 卡管理数组
int card_num = 0;       // 当前卡的数量
char num_sta = 0;
float money = 0;
char err = 0;
// 当前操作的卡号
char id[1024] = {0};

int main()
{

    // 1.映射LCD 设备
    mmap_lcd();

    // 2.初始化字库
    init_font(25 * 2);

    // 显示一个键盘
    display_image("main.bmp");

    // 转换为字符串
    char text[1024] = {0};

    while (1)
    {
        // 获取触摸屏的坐标点
        int x, y;
        get_touch(&x, &y);

        // 判断坐标点，显示对应的数字
        int value = Keyboard(x, y);
        printf("value=%d\n", value);

        // 判断是否为是数字
        if (value >= 0 && value <= 9)
        {
            char num[10];
            sprintf(num, "%d", value);
            // 限制金额的位数
            if (strlen(text) >= 10)
            {
                continue;
            }
            else
            {
                // 把转换后的字符串追加到text中
                strcat(text, num);
                num_sta++;
            }

            // 显示text
            show_text(30, 20, 290, 40, text, 0x0, 800);
        }

        // 判断是否为点
        if (value == -1)
        {
            if (num_sta == 0)
            {
                continue;
            }
            else
            {
                char num[10];
                sprintf(num, ".");
                strcat(text, num);
                num_sta++;
            }

            // 显示text
            show_text(30, 20, 290, 40, text, 0x0, 800);
        }

        // 判断是否为读卡
        if (value == 99)
        {
            if (get_rfid(id) != NULL)
            {
                show_text(460, 420, 190, 40, id, 0x0, 0);
            }
        }

        // 判断是否为退格
        if (value == -4)
        {
            num_sta--;
            text[num_sta] = '\0';
            show_text(30, 20, 290, 40, text, 0x0, 800);
        }

        if (value == -5)
        {
            num_sta = 0;
            memset(text, 0, 1024);
            show_text(30, 20, 290, 40, text, 0x0, 800);
        }

        if (value == -2)
        {
            money = atoi(text);
        }

        if (value == -3)
        {
            money = 0;
        }

        // 判断是否为注册按钮
        if (value == 88)
        {
            // 遍历数组看看当前的卡号是否已经注册
            int i = 0;
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    show_text(420, 0, 380, 60, "卡号已经存在,注册失败", 0x00ff0000, 500);
                    break;
                }
            }

            // 当前卡号不存在，注册成功
            if (strlen(id) > 0 && i == card_num)
            {
                strcpy(arry[card_num].rfid, id);
                arry[card_num].money = 0;
                card_num++;
                show_text(420, 0, 380, 60, "注册成功卡上余额0元", 0x00ff0000, 500);
            }
        }

        // 判断是否为注销按钮
        if (value == 77)
        {
            // 遍历数组看看当前的卡号是否已经注册
            int i = 0;
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    err = 0;
                    break;
                }
                err = 1;
            }
            if (err = 1 && strlen(id) > 0 && i == card_num)
                show_text(420, 0, 380, 60, "卡号不存在，注销失败", 0x00ff0000, 500);
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    // 将数组后面的元素向前移动
                    for (int j = i; j < card_num - 1; j++)
                    {
                        arry[j] = arry[j + 1];
                    }
                    card_num--; // 更新卡号数量
                    show_text(420, 0, 380, 60, "注销成功", 0x00ff0000, 500);
                    break;
                }
                else
                    show_text(420, 0, 380, 60, "卡号不存在，注销失败", 0x00ff0000, 500);
            }
        }
        
        // 判断是否为查询按钮
        if (value == 66)
        {
            // 遍历数组看看当前的卡号是否已经注册
            int i = 0;
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    err = 0;
                    break;
                }
                err = 1;
            }
            if (err = 1 && strlen(id) > 0 && i == card_num)
                show_text(420, 0, 380, 60, "卡号不存在，查询失败", 0x00ff0000, 500);
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    char text[100] = {0};
                    sprintf(text,"当前余额为%d",arry[i].money);
                    show_text(420, 0, 380, 60, text, 0x00ff0000, 500);
                    break;
                }
            }
        }

        // 判断是否为充值按钮
        if (value == 55)
        {
            // 遍历数组看看当前的卡号是否已经注册
            int i = 0;
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    err = 0;
                    break;
                }
                err = 1;
            }
            if (err = 1 && strlen(id) > 0 && i == card_num)
                show_text(420, 0, 380, 60, "卡号不存在，充值失败", 0x00ff0000, 500);
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    arry[i].money += money;
                    char text[100] = {0};
                    sprintf(text,"充值成功卡上余额%d元",arry[i].money);
                    show_text(420, 0, 380, 60, text, 0x00ff0000, 500);
                    break;
                }
            }
        }

        // 判断是否为消费按钮
        if (value == 44)
        {
            // 遍历数组看看当前的卡号是否已经注册
            int i = 0;
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    err = 0;
                    break;
                }
                err = 1;
            }
            if (err = 1 && strlen(id) > 0 && i == card_num)
                show_text(420, 0, 380, 60, "卡号不存在，消费失败", 0x00ff0000, 500);
            for (i = 0; i < card_num; i++)
            {
                if (strcmp(arry[i].rfid, id) == 0) // 卡号存在
                {
                    if(money > arry[i].money)
                    {
                        show_text(420, 0, 380, 60, "余额不足，消费失败", 0x00ff0000, 500);
                        break;
                    }
                    arry[i].money -= money;
                    char text[100] = {0};
                    sprintf(text,"消费成功卡上余额%d元",arry[i].money);
                    show_text(420, 0, 380, 60, text, 0x00ff0000, 500);
                    break;
                }
            }
        }
    }
}